//-----------------------------------------------------------------------
// <copyright file="AddAssembly.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
// </copyright>
// <author>Andy Reeves</author>
// <email>andyr</email>
// <date>2004-03-23</date>
// <summary>Adds the specified assemblies to the CodeCoverage configuration file.</summary>
//-----------------------------------------------------------------------

namespace Microsoft.Sdc.Tasks.CodeCoverage
{
    using System;
    using System.IO;
    using Microsoft.Build.Framework;
    using System.Globalization;
    using System.Xml;

    /// <summary>
    /// Adds the specified assemblies to the CodeCoverage configuration file.
    /// </summary>
    /// <remarks>
    /// <code><![CDATA[<CodeCoverage.AddAssembly ReportDirectory="reportDirectory" AssemblyName="assemblyName" Assemblies="assemblies" Path="path"/>]]></code>
    /// <para>where:</para>
    /// <para><i>reportDirectory (Required)</i></para>
    /// <para>Full path to directory where reports will be placed. This directory must exist.</para>
    /// <para><i>assemblyName</i></para>
    /// <para>The name of the (single) assembly to be added to the CodeCoverage configuration file.</para>
    /// <para><i>assemblies</i></para>
    /// <para>The names of the assemblies to be added to the CodeCoverage configuration file.</para>
    /// <para><i>path</i></para>
    /// <para>The absolute path to the folder containing the CodeCoverage configuration file. This defaults to being retrieved from the registry.</para>
    /// </remarks>
    /// <example>
    /// <code><![CDATA[
    /// <Project>
    ///     <Target Name="Test" >
    ///         <CodeCoverage.AddAssembly
    ///             ReportDirectory="C:\ReportDirectory"
    ///             Assembly="MyNamespace.MyAssembly.dll"
    ///             Path="C:\CoverageEyeInstallation\Configuration"  />
    ///     </Target>
    /// </Project>
    /// ]]></code>    
    /// </example>
    public class AddAssembly : TaskBase
    {
        private string path = String.Empty;
        private string assemblyName = String.Empty;
        private string reportDirectory = String.Empty;
        private string[] assemblies = new string[0];

        /// <summary>
        /// Initializes a new instance of the AddAssembly class.
        /// </summary>
        public AddAssembly()
        {
        }

        /// <summary>
        /// The full path to the CoverageEye configuration directory. The assembly/assemblies specified will be added to the "CoverageConfiguration.xml" 
        /// CoverageEye configuration file. It defaults to the default position stored in the registry.
        /// </summary>
        /// <value>The full path containing the CoverageEye executable</value>
        public string Path
        {
            get
            {
                return (this.path == null ? String.Empty : this.path);
            }

            set
            {
                this.path = value;
            }
        }

        /// <summary>
        /// The name of the assembly to be added to the CoverageEye configuration file. This property should not be set if the Assemblies property has previously
        /// been set. 
        /// </summary>
        /// <value>The assembly name, not the full path, as CoverageEye works against loaded assemblies in the JIT.</value>
        public string AssemblyName
        {
            get
            {
                return (this.assemblyName == null ? String.Empty : this.assemblyName);
            }

            set
            {
                this.assemblyName = value;
            }
        }

        /// <summary>
        /// The list of assembly names to be added to the CoverageEye configuration file. This property should not be set if the AssemblyName property has previously
        /// been set. 
        /// </summary>
        /// <value>The list of assembly names, not their full paths, as CoverageEye works against loaded assemblies in the JIT.</value>
        public string[] Assemblies
        {
            get
            {
                return (this.assemblies == null ? new string[0] : this.assemblies);
            }

            set
            {
                this.assemblies = value;
            }
        }

        /// <summary>
        /// Full path to directory where reports will be placed. This directory must exist.
        /// </summary>
        /// <value>Defaults to String.Empty</value>
        [Required]
        public string ReportDirectory
        {
            get
            {
                return (this.reportDirectory == null ? String.Empty : this.reportDirectory);
            }

            set
            {
                this.reportDirectory = value;
            }
        }

        /// <summary>
        /// Performs the action of this task.
        /// </summary>
        protected override void InternalExecute()
        {
            #region Execute code

            if (this.path == null || this.path.Length == 0)
            {
                // assume using default position             

                string key1 = @"CLSID\{18656C37-035D-41CD-82C2-85DEF2DD5F7B}\InprocServer32";
                Microsoft.Win32.RegistryKey regKey = null;
                regKey = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(key1);

                if (regKey != null)
                {
                    string regValue = null;
                    regValue = regKey.GetValue(null).ToString();
                    if (regValue != null)
                    {
                        string pathToConfig = String.Empty;

                        System.IO.FileInfo fileinfo = new FileInfo(regValue);
                        pathToConfig = (fileinfo.DirectoryName + "\\Configuration\\");
                        this.path = pathToConfig;
                    }
                    else
                    {
                        throw new TaskException("CodeCoverage.NotRegistered");
                    }
                    regKey.Close();
                }
                else
                {
                    throw new TaskException("CodeCoverage.NotRegistered");
                }
            }

            /*
            <Assembly
                    Owner="codecoverage@microsoft.com"
                    Description="Test Assembly"
                    AssemblyName="consoleapplication1.exe"
                    ReportDirectory="c:\temp">
            </Assembly>
            */

            if (this.Assemblies.Length == 0 && this.AssemblyName.Length == 0)
            {
                throw new TaskException("CodeCoverage.AssemblyNotSpecified");
            }

            if (this.Assemblies.Length != 0 && this.AssemblyName.Length > 0)
            {
                throw new TaskException("CodeCoverage.AssemblyNameAndAssembliesSpecified");
            }

            // open xml document
            XmlDocument document = new XmlDocument();
            document.Load(this.path + "CoverageConfiguration.xml");
            
            // xpath to assemblies
            XmlElement element = document.DocumentElement;

            if (this.AssemblyName.Length > 0)
            {
                // Just add the single assembly name into the configuration.
                XmlDocumentFragment fragment = document.CreateDocumentFragment();
                fragment.InnerXml = "<Assembly AssemblyName=\"" + this.AssemblyName.ToLower(CultureInfo.InvariantCulture) + "\" ReportDirectory=\"" + this.ReportDirectory + "\"/>";
                
                // add the new node
                element.AppendChild(fragment);
            }
            else
            {
                foreach (string assemblyName in this.Assemblies)
                {
                    XmlDocumentFragment fragment = document.CreateDocumentFragment();
                    fragment.InnerXml = "<Assembly AssemblyName=\"" + assemblyName.ToLower(CultureInfo.InvariantCulture) + "\" ReportDirectory=\"" + this.ReportDirectory + "\"/>";
                    
                    // add the new node
                    element.AppendChild(fragment);
                }
            }

            // save the xml file.
            document.Save(this.path + "CoverageConfiguration.xml");
            #endregion
        }
    }
}
